#include <stdio.h>
#include <string.h>

#include "driver/uart.h"
#include "driver/gpio.h"
#include "sdkconfig.h"
#include "esp_log.h"
#include "esp_task_wdt.h"
#include "esp_intr_alloc.h"

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"

#include "my_uart.h"
#include "sleep.h"

/**
 * This is an example which echos any data it receives on configured UART back to the sender,
 * with hardware flow control turned off. It does not use UART driver event queue.
 *
 * - Port: configured UART
 * - Receive (Rx) buffer: on
 * - Transmit (Tx) buffer: off
 * - Flow control: off
 * - Event queue: off
 * - Pin assignment: see defines below (See Kconfig)
 */

#define ECHO_TEST_TXD 12
#define ECHO_TEST_RXD 14
#define ECHO_TEST_RTS (UART_PIN_NO_CHANGE)
#define ECHO_TEST_CTS (UART_PIN_NO_CHANGE)

#define ECHO_UART_PORT_NUM      2
#define ECHO_UART_BAUD_RATE     9600
#define ECHO_TASK_STACK_SIZE    4096

#define HUMAN_MODE 0
#define OBJECT_MODE 1

#define RECV_BUF_SIZE (1024)
#define SEND_BUF_SIZE (5)

#define EX_UART_NUM UART_NUM_0
#define PATTERN_CHR_NUM    (3)         /*!< Set the number of consecutive and identical characters received by receiver which defines a UART pattern*/

#define BUF_SIZE (1024)
#define RD_BUF_SIZE (BUF_SIZE)

static const int mode = OBJECT_MODE;
static const char *TAG = "MY_UART";

static char *mode_char = "0";
static char flag = 1;

static QueueHandle_t uart0_queue;

int loop_cnt = 0;

static void uart_event_task(void *pvParameters)
{
    uart_event_t event;
    size_t buffered_size;
    uint8_t* dtmp = (uint8_t*) malloc(RD_BUF_SIZE);
    for(;;) {
        //Waiting for UART event.
        if(xQueueReceive(uart0_queue, (void * )&event, (portTickType)portMAX_DELAY)) {
            bzero(dtmp, RD_BUF_SIZE);
            ESP_LOGI(TAG, "uart[%d] event:", EX_UART_NUM);
            switch(event.type) {
                //Event of UART receving data
                /*We'd better handler data event fast, there would be much more data events than
                other types of events. If we take too much time on data event, the queue might
                be full.*/
                case UART_DATA:
                    // ESP_LOGI(TAG, "[UART DATA]: %d", event.size);
                    // ESP_LOGI(TAG, "[DATA EVT]:");
                    break;
                //Event of HW FIFO overflow detected
                case UART_FIFO_OVF:
                    ESP_LOGI(TAG, "hw fifo overflow");
                    flag = 0;
                    // If fifo overflow happened, you should consider adding flow control for your application.
                    // The ISR has already reset the rx FIFO,
                    // As an example, we directly flush the rx buffer here in order to read more data.
                    uart_flush_input(EX_UART_NUM);
                    xQueueReset(uart0_queue);
                    break;
                //Event of UART ring buffer full
                case UART_BUFFER_FULL:
                    ESP_LOGI(TAG, "ring buffer full");
                    flag = 0;
                    // If buffer full happened, you should consider encreasing your buffer size
                    // As an example, we directly flush the rx buffer here in order to read more data.
                    uart_flush_input(EX_UART_NUM);
                    xQueueReset(uart0_queue);
                    break;
                //Event of UART RX break detected
                case UART_BREAK:
                    ESP_LOGI(TAG, "uart rx break");
                    flag = 0;
                    break;
                //Event of UART parity check error
                case UART_PARITY_ERR:
                    ESP_LOGI(TAG, "uart parity error");
                    flag = 0;
                    break;
                //Event of UART frame error
                case UART_FRAME_ERR:
                    flag = 0;
                    ESP_LOGI(TAG, "uart frame error");
                    break;
                //UART_PATTERN_DET
                case UART_PATTERN_DET:
                    uart_get_buffered_data_len(EX_UART_NUM, &buffered_size);
                    int pos = uart_pattern_pop_pos(EX_UART_NUM);
                    ESP_LOGI(TAG, "[UART PATTERN DETECTED] pos: %d, buffered size: %d", pos, buffered_size);
                    if (pos == -1) {
                        // There used to be a UART_PATTERN_DET event, but the pattern position queue is full so that it can not
                        // record the position. We should set a larger queue size.
                        // As an example, we directly flush the rx buffer here.
                        uart_flush_input(EX_UART_NUM);
                    } else {
                        uint8_t pat[PATTERN_CHR_NUM + 1];
                        memset(pat, 0, sizeof(pat));
                        ESP_LOGI(TAG, "read data: %s", dtmp);
                        ESP_LOGI(TAG, "read pat : %s", pat);
                    }
                    break;
                //Others
                default:
                    ESP_LOGI(TAG, "uart event type: %d", event.type);
                    break;
            }
        }
    }
    free(dtmp);
    dtmp = NULL;
    vTaskDelete(NULL);
}

static int measure()
{
    // Configure the initial dataset
    uint8_t *data = (uint8_t *)malloc(RECV_BUF_SIZE); // 32 elements maximum for received data
    uint8_t *mode_data = (uint8_t *)malloc(SEND_BUF_SIZE); // temperature measuring mode HEX data
    uint8_t *start_sig = (uint8_t *)malloc(SEND_BUF_SIZE); // start signal to measure temperature
    int temprature = 0;
    int len = 0;

    *start_sig = 0xFA;
    *(start_sig+1) = 0xCA;
    *(start_sig+2) = 0xC4;


    // if(test_status() == 1){
    //     return 1;
    // }

    if (mode == HUMAN_MODE)
    {
        *mode_data = 0xFA;
        *(mode_data+1) = 0xC5;
        *(mode_data+2) = 0xBF;
        mode_char = "体温模式";
        /* code */
    }
    else if (mode == OBJECT_MODE)
    {
        *mode_data = 0xFA;
        *(mode_data+1) = 0xC6;
        *(mode_data+2) = 0xC0;
        mode_char = "物温模式";
        /* code */
    }
    uart_write_bytes(ECHO_UART_PORT_NUM, (const uint8_t *) mode_data, SEND_BUF_SIZE); //写入测温模式数据    
    ESP_LOGI(TAG, "-----测温模式设置成功，当前模式为：%s-----", mode_char);

    vTaskDelay(100 / portTICK_PERIOD_MS); //延时100ms  


    while(flag == 1){
        if (0 == loop_cnt % 10) {

            ESP_LOGI(TAG, "-----开始测温-----");
            // if (150 == loop_cnt % 300) {
            //     light_publish(pclient,ON);
            // }

            
            int count = 0;
            while (len == 0 || data[0] == 0)
            {
                //发送测温指令 
                uart_write_bytes(ECHO_UART_PORT_NUM, (const uint8_t *) start_sig, SEND_BUF_SIZE);   
                // Read data from the UART
                len = uart_read_bytes(ECHO_UART_PORT_NUM, (const uint8_t *) data, (RECV_BUF_SIZE - 1), 20 / portTICK_RATE_MS);
                ESP_LOGI(TAG, "-----温度已更新-----");
                vTaskDelay(1000 / portTICK_PERIOD_MS); //延时1000ms
                if(count > 10){
                    // 向物联网平台报障，数据收发端口连接中断。
                    ESP_LOGI(TAG, "-----设备连接中断-----");
                }else{
                    count++;
                }
            }

            if (len) {
                data[len] = '\0';
                // ESP_LOGI(TAG, "Recv str: %02x", (uint8_t *) data);
                printf("\n");
                for (int i = 0; i < len; i++) {
                    printf("%02X ", data[i]);
                }
                printf("\n");
                ESP_LOGI(TAG, "温度: %02u.%02u 摄氏度", data[2], data[3]);
                temprature = data[2] * 100 + data[3];          
                ESP_LOGI(TAG, "温度*100: %d", temprature);
            }
            for (int i = 0; i < len; i++) //清空所有温度数据
            {
                data[i] = 0;
            }
            
            ESP_LOGI(TAG, "-----结束测温-----");
        }
        loop_cnt += 1;
        vTaskDelay(1000 / portTICK_PERIOD_MS); //延时100ms
    }
    if(flag == 0){
        ESP_LOGI(TAG, "-----设备连接中断-----");
        return 1;
    }
    return 0;
}


void uart_main(void)
{
    /* Configure parameters of an UART driver,
     * communication pins and install the driver */
    uart_config_t uart_config = {
        .baud_rate = ECHO_UART_BAUD_RATE,
        .data_bits = UART_DATA_8_BITS,
        .parity    = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
        .source_clk = UART_SCLK_APB,
    };
    int intr_alloc_flags = 0;
    int is_task_stop = 0;

    #if CONFIG_UART_ISR_IN_IRAM
        intr_alloc_flags = ESP_INTR_FLAG_IRAM;
    #endif

    ESP_ERROR_CHECK(uart_driver_install(ECHO_UART_PORT_NUM, RECV_BUF_SIZE * 2, 0, 5, &uart0_queue, intr_alloc_flags));
    ESP_ERROR_CHECK(uart_param_config(ECHO_UART_PORT_NUM, &uart_config));
    ESP_ERROR_CHECK(uart_set_pin(ECHO_UART_PORT_NUM, ECHO_TEST_TXD, ECHO_TEST_RXD, ECHO_TEST_RTS, ECHO_TEST_CTS));
    
    //TODO: 串口QUEUE队列和分包组包拆包

    // //Set uart pattern detect function. 
    // uart_enable_pattern_det_baud_intr(EX_UART_NUM, '+', PATTERN_CHR_NUM, 9, 0, 0);
    //Reset the pattern queue length to record at most 5 pattern positions.
    uart_pattern_queue_reset(EX_UART_NUM, 5);

    // xTaskCreate(uart_event_task, "uart_event_task", 2048, NULL, 12, NULL);
    while(1){
        if(is_task_stop == 1){
            vTaskDelay(5000 / portTICK_PERIOD_MS);
            ESP_LOGI(TAG, "-----重新连接设备中-----");
        }
        is_task_stop = measure();
    }
}

